/* 
 * File:   MemoryManagerForAllocatorPoolBased.h
 * Author: root
 *
 * Created on 8 listopad 2011, 17:48
 */

#ifndef MEMORYMANAGERFORALLOCATORPOOLBASED_H
#define	MEMORYMANAGERFORALLOCATORPOOLBASED_H

#include "AllocatorPoolBased.h"
#include "Handles.h"

#include <boost/assert.hpp>
#include <boost/scoped_ptr.hpp>
using boost::scoped_ptr;

template
<unsigned int _HowManyAllocatorsInManager, unsigned int _HowmanyHandlesMemory, typename _DataType>
class MemoryManagerForAllocatorPoolBased
{
public:

    typedef AllocatorPoolBased<_DataType> Allocator;
    typedef Handle<Allocator,16> HandleAllocator;
    typedef scoped_ptr<Allocator> WrapedAllorator;
    typedef Handles<HandleAllocator, WrapedAllorator,  _HowManyAllocatorsInManager> HandlesAllocator;
    typedef Handle<_DataType* ,8> HandleMemory;
    typedef Handles<HandleMemory, _DataType*,  _HowmanyHandlesMemory> HandlesMemory;

    class HandleAllocatorMemory
    {
    public:
        HandleAllocator handleAllocator;
        HandleMemory handlesMemory;
    };

    

    MemoryManagerForAllocatorPoolBased()
    {
        
    }

    HandleAllocator acquireHandleAllocator()
    {
        return handlesAllocator.acquire();
    }

    void releaseHandleAllocator(HandleAllocator handleAllocator)
    {
        handlesAllocator.dereference(handleAllocator)->reset(NULL);
        handlesAllocator.release(handleAllocator);
    }

    WrapedAllorator* dereferenceHandleAllocator(HandleAllocator handleAllocator)
    {
        return handlesAllocator.dereference(handleAllocator);
    }

    HandleAllocatorMemory acquireHandleAllocatorMemory(HandleAllocator handleAllocator)
    {
        HandleAllocatorMemory returnedHandleAllocatorMemory;
        returnedHandleAllocatorMemory.handleAllocator=handleAllocator;
        returnedHandleAllocatorMemory.handlesMemory=handlesMemory.acquire();

        BOOST_ASSERT_MSG(handlesAllocator.dereference(handleAllocator)->get()!=NULL,"handleAllocator is  NULL, initialize allocator first");

        *handlesMemory.dereference(returnedHandleAllocatorMemory.handlesMemory)=
                (*handlesAllocator.dereference(handleAllocator))->allocate(1);

        return returnedHandleAllocatorMemory;
    }

    void releaseHandleAllocatorMemory(HandleAllocatorMemory handleAllocatorMemory)
    {
        BOOST_ASSERT_MSG(handlesAllocator.dereference( handleAllocatorMemory.handleAllocator)->get()!=NULL,"handleAllocator is dereferenced to NULL pointer");

        (*handlesAllocator.dereference( handleAllocatorMemory.handleAllocator))->
                deallocate(*handlesMemory.dereference(handleAllocatorMemory.handlesMemory),1);

        handlesMemory.release(handleAllocatorMemory.handlesMemory);
    }

    _DataType* dereferenceHandleAllocatorMemory(HandleAllocatorMemory handleAllocatorMemory)
    {
        BOOST_ASSERT_MSG(handlesAllocator.dereference( handleAllocatorMemory.handleAllocator)->get()!=NULL,"handleAllocator is dereferenced to NULL pointer");

        return *handlesMemory.dereference(handleAllocatorMemory.handlesMemory);
    }

private:
    MemoryManagerForAllocatorPoolBased(MemoryManagerForAllocatorPoolBased&);
    MemoryManagerForAllocatorPoolBased& operator=(MemoryManagerForAllocatorPoolBased&);

    HandlesAllocator handlesAllocator;
    HandlesMemory handlesMemory;

};


#endif	/* MEMORYMANAGERFORALLOCATORPOOLBASED_H */

